package com.acdc.dlt698.parser;

import com.acdc.dlt698.constants.DataType;
import com.acdc.dlt698.constants.GetResponse;
import com.acdc.dlt698.constants.GetResultType;
import com.acdc.dlt698.constants.ServerAPDU;
import com.acdc.dlt698.entity.GetResponseNormalData;
import com.acdc.dlt698.entity.GetResponseNormalFrame;
import com.acdc.dlt698.constants.OI;
import com.acdc.dlt698.entity.ForwardPower;
import com.acdc.dlt698.entity.OAD; 

import com.acdc.dlt698.entity.FrameDto;
import com.acdc.dlt698.utils.FrameParseUtils;
import com.acdc.dlt698.utils.HexUtils;
import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Date;

@Slf4j
@Component("getResponseNormalFrameParser")
public class GetResponseNormalFrameParser implements BaseFrameParser<GetResponseNormalFrame,GetResponseNormalData> {
    @Override
    public GetResponseNormalFrame parseFrame(byte[] frameBytes) throws RuntimeException{
        // 去除FE FE FE FE
        if(frameBytes[0] == (byte)0xFE){
            int i = 0;
            while(i < frameBytes.length && frameBytes[i] == (byte)0xFE){
                i++;
            }
            frameBytes = Arrays.copyOfRange(frameBytes, i, frameBytes.length);
        }
        GetResponseNormalFrame frame  = new GetResponseNormalFrame();
        if(!FrameParseUtils.checkFrame(frameBytes)){
            String errorInfo = "无效帧：起始符或结束符错误,当前帧起始符--"+HexUtils.byteToHex(frameBytes[0])+",结束符--"+HexUtils.byteToHex(frameBytes[frameBytes.length-1]);
            log.error(errorInfo);
            throw new RuntimeException(errorInfo);
        }
        FrameDto frameDto = FrameParseUtils.getFrameDto(frameBytes);
        GetResponseNormalData getResponseNormalData = this.parseLinkUserData(frameDto.getUserData());
        frame.setLengthDomain(frameDto.getLengthDomain());
        frame.setControlDomain(frameDto.getControlDomain());
        frame.setAddressDomain(frameDto.getAddressDomain());
        frame.setHcs(frameDto.getHcs());
        frame.setNormalData(getResponseNormalData);
        frame.setFcs(frameDto.getFcs());
        return frame;
    }

    @Override
    public GetResponseNormalData parseLinkUserData(byte[] userDataBytes){
        GetResponseNormalData normalData = new GetResponseNormalData();
        log.info("用户完整数据{}", HexUtils.bytesToHex(userDataBytes));
        // 如果 userDataBytes以 0x90开始，丢弃前三个
        if(userDataBytes[0] == (byte)0x90){
            userDataBytes = Arrays.copyOfRange(userDataBytes, 3, userDataBytes.length);
            log.info("丢弃前三个字节后用户完整数据{}", HexUtils.bytesToHex(userDataBytes));
        }
        normalData.setApdu(userDataBytes[0]);
        byte apduByte = userDataBytes[0];
        // 这是客户端发起的请求
        ServerAPDU serverAPDU = ServerAPDU.getServerAPDUBySign(apduByte);
        if(serverAPDU != null){
            normalData.setServerAPDU(serverAPDU);
        }
        byte responseTypeByte = userDataBytes[1];
        GetResponse getResponse = GetResponse.getResponseBySign(responseTypeByte);
        normalData.setGetResponse(getResponse);

        normalData.setPIID(userDataBytes[2]);

        byte[] oadBytes = new byte[4];
        System.arraycopy(userDataBytes,3,oadBytes,0,4);
        normalData.setOadBytes(oadBytes);
        OAD oad = FrameParseUtils.parseOAD(oadBytes);
        
        GetResultType getResultType = GetResultType.getResultTypeBySign(userDataBytes[7]);
        if(getResultType != null){
            if(getResultType.equals(GetResultType.ERROR)){
                log.error("请求错误{}", GetResultType.ERROR.getDesc());
                throw new RuntimeException(GetResultType.ERROR.getDesc());
            }
            oad.setGetResultType(getResultType);
        }

        DataType dataTypeBySign = DataType.getDataTypeBySign(userDataBytes[8]);
        oad.setDataType(dataTypeBySign);
        int offset = 8;
        if(dataTypeBySign.getLength() == 0){
            offset = 9;
            normalData.setLength(userDataBytes[offset]);
        }else{
            // 长度需要减去FollowReport和TimeTag
            normalData.setLength(userDataBytes.length-(offset+1)-2);
        }
        byte[] result = new byte[normalData.getLength()];
        System.arraycopy(userDataBytes,offset+1,result,0,normalData.getLength());
        oad.setData(result);
        normalData.setOad(oad);

        normalData.setTimeTag(userDataBytes[userDataBytes.length-1]);

        return normalData;
    }

    @Override
    public Object getData(GetResponseNormalFrame frame) throws RuntimeException {
        
        switch(frame.getNormalData().getOad().getOi()){
            case PAEE:
                ForwardPower forwardPower = new ForwardPower();
                forwardPower.setServerAddress(frame.getAddressDomain().getServerAddress());
                Float pwoer = parseForwardPower(frame.getNormalData().getOad().getData());
                forwardPower.setPower(pwoer);
                forwardPower.setPhase("ALL");
                forwardPower.setCollectionTime(new Date());
                return forwardPower;
            case A_PAEE:
                forwardPower = new ForwardPower();
                forwardPower.setServerAddress(frame.getAddressDomain().getServerAddress());
                pwoer = parseForwardPower(frame.getNormalData().getOad().getData());
                forwardPower.setPower(pwoer);
                forwardPower.setPhase("A");
                forwardPower.setCollectionTime(new Date());
                return forwardPower;
            case B_PAEE:
                forwardPower = new ForwardPower();
                forwardPower.setServerAddress(frame.getAddressDomain().getServerAddress());
                pwoer = parseForwardPower(frame.getNormalData().getOad().getData());
                forwardPower.setPower(pwoer);
                forwardPower.setPhase("B");
                forwardPower.setCollectionTime(new Date());
                return forwardPower;
            case C_PAEE:
                forwardPower = new ForwardPower();
                forwardPower.setServerAddress(frame.getAddressDomain().getServerAddress());
                pwoer = parseForwardPower(frame.getNormalData().getOad().getData());
                forwardPower.setPower(pwoer);
                forwardPower.setPhase("C");
                forwardPower.setCollectionTime(new Date());
                return forwardPower;
            case MAIL_ADDRESS:
                // 返回服务器地址  
                return frame.getAddressDomain().getServerAddress();
            default:
                return frame.getNormalData().getOad().getData();
        }
    }

    private Float parseForwardPower(byte[] data){
        byte[] dataBytes = Arrays.copyOfRange(data, 2, 6);
        log.info("正向有功电能数据{}", HexUtils.bytesToHex(dataBytes));
        Object rawData = FrameParseUtils.getData(DataType.DOUBLE_LONG_UNSIGNED, dataBytes);
        log.info("解析后正向有功电能数据{}", rawData);
        return ((Number) rawData).floatValue() / 100.0f;
    }

}
